//
//  LMImageStroke.swift
//  LMScreenshotHint
//
//  Created by LaiMing on 2021/4/12.
//

import UIKit
import Foundation


/// 画笔操作类型
public enum LMImageStrokeOperationType:Int {
    
    /// 没有操作
    case None = 0
    
    /// 马赛克模糊
    case MosaicFuzzy
    
    /// 画笔
    case Srtoke
}



class LMDrawTouchPointImageView: UIImageView {
        
    private let drawView:LMStrokeDrawTouchView = LMStrokeDrawTouchView.init(frame: CGRect.zero)
    
    /// 画笔颜色
    private var lineColor:UIColor = .red
    
    /// 线条宽度
    private var lineWidth:CGFloat = 8
    
    //每个颜色值8bit
    private let kBitsPerComponent = 8
    private let kPixelChannelCount = 4
    private let kBitsPerPixel = 32
    

    /// 当前操作类型
    public var currentOperation:LMImageStrokeOperationType = .None {
        
        didSet{
            
            drawView.operationType = currentOperation
        }
    }
    
    /// 构造函数
    /// - Parameters:
    ///   - newImage: <#newImage description#>
    ///   - newFrame: <#newFrame description#>
    ///   - lineWidth: <#lineWidth description#>
    ///   - lineColor: <#lineColor description#>
    convenience init(newImage:UIImage ,
                     newFrame:CGRect ,
                     lineWidth:CGFloat ,
                     lineColor:UIColor) {
        
        self.init()
        
        self.frame = newFrame
        self.image = newImage
        self.lineColor = lineColor
        self.lineWidth = lineWidth
        
        self.drawView.mosaicFuzzyLayerImage = transToMosaicImage(orginImage: newImage) ?? newImage
        addSubview(self.drawView)
    }
    

    override func layoutSubviews() {
        super.layoutSubviews()

        drawView.frame = CGRect.init(origin: CGPoint.zero,
                                     size: bounds.size)

//        print("drawView.frame-->\(drawView.frame)")

    }
    
    
    
    /// 获取马赛克后的图片
    /// - Parameters:
    ///   - orginImage: <#orginImage description#>
    ///   - level: <#level description#>
    /// - Returns: <#description#>
    private func transToMosaicImage(orginImage:UIImage , level:Int = 10) -> UIImage? {
        
        //获取BitmapData
        let colorSpace:CGColorSpace = CGColorSpaceCreateDeviceRGB()
        
        guard let imgRef:CGImage = orginImage.cgImage else {
            return nil
        }
        
        guard let context:CGContext = CGContext.init(data: nil,
                                                     width: imgRef.width,
                                                     height: imgRef.height,
                                                     bitsPerComponent: kBitsPerComponent, //每个颜色值8bit
                                                     bytesPerRow: imgRef.width*kPixelChannelCount,//每一行的像素点占用的字节数，每个像素点的ARGB四个通道各占8个bit
                                                     space: colorSpace,
                                                     bitmapInfo: CGImageAlphaInfo.premultipliedLast.rawValue) else {
            return nil
        }
        
        context.draw(imgRef, in: CGRect.init(x: 0,
                                             y: 0,
                                             width: imgRef.width,
                                             height: imgRef.height))
        
        guard let bitmapData:UnsafeMutableRawPointer = context.data else {
            return nil
        }
        
        //这里把BitmapData进行马赛克转换,就是用一个点的颜色填充一个level*level的正方形
        
        let pixel:UnsafeMutableRawPointer = UnsafeMutableRawPointer.allocate(byteCount: kPixelChannelCount,
                                                                             alignment: 1)
        
        var index:UInt = 0
        
        var preIndex:UInt = 0
        
        for i in 0...imgRef.height-1 {
            
            for j in 0...imgRef.width-1 {
                
                index = UInt(i * imgRef.width + j)
                
                if (i % level == 0) {
                    
                    if (j % level == 0) {
                        
                        memcpy(pixel, bitmapData + kPixelChannelCount*Int(index), kPixelChannelCount)
                        
                    }else{
                        
                        memcpy(bitmapData + kPixelChannelCount*Int(index), pixel, kPixelChannelCount)
                    }
                    
                } else {
                    
                    preIndex = UInt((i-1)*imgRef.width + j)
                    
                    memcpy(bitmapData + kPixelChannelCount*Int(index), bitmapData + kPixelChannelCount*Int(preIndex), kPixelChannelCount)
                }
            }
            
        }
        
        let dataLength:Int = imgRef.width * imgRef.height * kPixelChannelCount
        
        let provider:CGDataProvider = CGDataProvider.init(dataInfo: nil, data: bitmapData, size: dataLength) { (_, _, _) in
            
        }!
        
        //创建要输出的图像
        guard let mosaicImageRef:CGImage = CGImage.init(width: imgRef.width,
                                                        height: imgRef.height,
                                                        bitsPerComponent: kBitsPerComponent,
                                                        bitsPerPixel: kBitsPerPixel,
                                                        bytesPerRow: imgRef.width*kPixelChannelCount,
                                                        space: colorSpace,
                                                        bitmapInfo: .byteOrderMask,
                                                        provider: provider,
                                                        decode: nil,
                                                        shouldInterpolate: false,
                                                        intent: .defaultIntent) else {
            return nil
        }
        
        guard let outputContext:CGContext = CGContext.init(data: nil,
                                                           width: imgRef.width,
                                                           height: imgRef.height,
                                                           bitsPerComponent: kBitsPerComponent,
                                                           bytesPerRow: imgRef.width*kPixelChannelCount,
                                                           space: colorSpace,
                                                           bitmapInfo: CGImageAlphaInfo.premultipliedLast.rawValue) else {
            return nil
        }
        
        
        outputContext.draw(mosaicImageRef, in: CGRect.init(x: 0,
                                                           y: 0,
                                                           width: imgRef.width,
                                                           height: imgRef.height))
        
        guard let resultImageRef:CGImage = outputContext.makeImage() else {
            return nil
        }
        
        
        let scale:CGFloat = UIScreen.main.scale
        
        let resultImage:UIImage = UIImage.init(cgImage: resultImageRef,
                                               scale: scale,
                                               orientation: .up)
    
        return resultImage
    }
    
    
    
    /// 撤消操作
    public func revokeScreen() {
        
        drawView.revokeScreen()
    }
    
    
    /// 获取当前图片
    /// - Returns: 当前图片
    public func getImage() -> UIImage? {
            
        //1.开启一个位图上下文
        UIGraphicsBeginImageContextWithOptions(bounds.size, false, 0)
        
        //2.把画板上的内容渲染到上下文当中
        guard let ctx:CGContext = UIGraphicsGetCurrentContext() else {
            UIGraphicsEndImageContext()
            return nil
        }
        
        layer.render(in: ctx)
        
        //3.从上下文当中取出一张图片
        guard let newImage:UIImage = UIGraphicsGetImageFromCurrentImageContext() else {
            UIGraphicsEndImageContext()
            return nil
        }
        
        //4.关闭上下文
        UIGraphicsEndImageContext()
        
        return newImage;
    }
    
}



/// 画笔
fileprivate class LMImageSrtoke: NSObject {

    fileprivate var path:CGPath = CGMutablePath.init()
    
    fileprivate var blendMode:CGBlendMode = .normal
    
    fileprivate var strokeWidth:CGFloat = 1
    
    fileprivate var lineColor:UIColor = .red
    
    
    
    fileprivate func strokeWithContext(context:CGContext) {
        
        context.setStrokeColor(lineColor.cgColor)
        context.setFillColor(lineColor.cgColor)
        context.setLineWidth(strokeWidth)
        context.setBlendMode(blendMode)
        context.setLineJoin(.round)
        context.beginPath()
        context.addPath(path)
        context.strokePath()
    }
}


/// 画笔触摸view
fileprivate class LMStrokeDrawTouchView: UIView {
    
    //MARK: Attribute Declarations
    
    /// 是否擦除
    private var isEarse:Bool = false
    
    /// 画笔颜色
    private var lineColor:UIColor = .red
    
    /// 画笔线条宽度
    private var lineWidth:CGFloat = 8
    
    /// 画笔路径
    private var strokePath:CGMutablePath?
    

    /// 当前操作类型
    fileprivate var operationType:LMImageStrokeOperationType = .None
    
    
    /// 马赛克模糊图层
    private let mosaicFuzzyLayer:CALayer = CALayer.init()
    
    /// 马赛克模糊图层遮罩
    private let mosaicFuzzyShapeLayer:CAShapeLayer = CAShapeLayer.init()
    
    /// 马赛克模糊涂抹路径
    private var mosaicFuzzyPath:CGMutablePath = CGMutablePath.init()
    

    /// 存储所有的涂写路径( CGPath 、SMImageSrtoke)
    private var allPathArray:[AnyObject] = []
    
    
    //MARK: WillSet & Didset
    
    /// 马赛可模糊图层图片
    fileprivate var mosaicFuzzyLayerImage:UIImage = UIImage() {
        
        willSet{
            
            mosaicFuzzyLayer.contents = newValue.cgImage
        }
    }
    
    //MARK: Lift Cycle
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        
        backgroundColor = .clear
        
        //
        layer.addSublayer(mosaicFuzzyLayer)
        
        //
        mosaicFuzzyShapeLayer.lineCap = .round
        mosaicFuzzyShapeLayer.lineJoin = .round
        mosaicFuzzyShapeLayer.lineWidth = 40
        mosaicFuzzyShapeLayer.strokeColor = UIColor.blue.cgColor
        mosaicFuzzyShapeLayer.fillColor = nil
        layer.addSublayer(mosaicFuzzyShapeLayer)
        
        mosaicFuzzyLayer.mask = mosaicFuzzyShapeLayer
        
    }
    
    override func layoutSublayers(of layer: CALayer) {
        super.layoutSublayers(of: layer)
        
        mosaicFuzzyLayer.frame = bounds
        mosaicFuzzyShapeLayer.frame = bounds
    }

    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    deinit {
        
        strokePath?.closeSubpath()
    }
    
    
    override func draw(_ rect: CGRect) {

        switch operationType {
        case .Srtoke:
            if let context:CGContext = UIGraphicsGetCurrentContext() {

                for (_,pathObject) in allPathArray.enumerated() {
                    
                    if pathObject.isKind(of: LMImageSrtoke.self) {
                        
                        let srtoke:LMImageSrtoke = pathObject as! LMImageSrtoke
                        
                        srtoke.strokeWithContext(context: context)
                    }
                }
            }

        default:
            break
        }

    }
    
    //MARK: Init Data & UI
    
    //MARK: Private Method
    
    /// 触摸开始事件
    /// - Parameters:
    ///   - touches: <#touches description#>
    ///   - event: <#event description#>
    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        
        super.touchesBegan(touches, with: event)
        
        switch operationType {
        case .Srtoke:
            strokePath = CGMutablePath.init()
            
            let stroke:LMImageSrtoke = LMImageSrtoke.init()
            stroke.path = strokePath!
            stroke.blendMode = isEarse ? .destinationIn : .normal
            stroke.strokeWidth = isEarse ? 20 : lineWidth
            stroke.lineColor = isEarse ?  .clear : lineColor
            allPathArray.append(stroke)
            
            if let touch:UITouch = touches.first {
                
                let point:CGPoint = touch.location(in: self)
                
                strokePath?.move(to: point)
            }
            
        case .MosaicFuzzy:
            
            if let touch:UITouch = touches.first {
                
                let point:CGPoint = touch.location(in: self)
                
                mosaicFuzzyPath.move(to: point)
                
                let newPath:CGMutablePath = mosaicFuzzyPath.mutableCopy()!
                mosaicFuzzyShapeLayer.path = newPath
                
            }
            
        default:
            break
        }
        
    }
    
    
    /// 触摸移动事件
    /// - Parameters:
    ///   - touches: <#touches description#>
    ///   - event: <#event description#>
    override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
        
        super.touchesMoved(touches, with: event)
        
        
        switch operationType {
        case .Srtoke:
            if let touch:UITouch = touches.first {
                
                let point:CGPoint = touch.location(in: self)
                
                strokePath?.addLine(to: point)
                
                setNeedsDisplay()
            }
            
        case .MosaicFuzzy:
            if let touch:UITouch = touches.first {
                
                let point:CGPoint = touch.location(in: self)
                
                mosaicFuzzyPath.addLine(to: point)
                
                let newPath:CGMutablePath = mosaicFuzzyPath.mutableCopy()!
                mosaicFuzzyShapeLayer.path = newPath
            
            }
            
        default:
            break
        }
        
    }
    
    
    /// 触摸结束事件
    /// - Parameters:
    ///   - touches: <#touches description#>
    ///   - event: <#event description#>
    override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
        super.touchesEnded(touches, with: event)
        
        if operationType == .MosaicFuzzy && mosaicFuzzyShapeLayer.path != nil {
            
            allPathArray.append(mosaicFuzzyShapeLayer.path!)

        }
    }
    
    //MARK: Public Method
    
    /// 清屏
    public func clearScreen() {
        
        isEarse = false
        
        allPathArray.removeAll()

        mosaicFuzzyShapeLayer.path = nil
        mosaicFuzzyPath = CGMutablePath.init()
        
        strokePath = CGMutablePath.init()
        
        setNeedsDisplay()
    }
    
    
    /// 撤消操作
    public func revokeScreen() {
        
        
        guard allPathArray.count > 0 else {
            
            clearScreen()
            return
        }
        
        isEarse = false
        
        
        // 判断最后一个元素是什么 （这里有个坑，用is CGPath直接判断，SMImageSrtoke也是为true,所以只能用isKind先判断画笔类型）
        var needOperationType:LMImageStrokeOperationType = .None
        
        let lastObject = allPathArray.last
        
        
        if lastObject!.isKind(of: LMImageSrtoke.self) {
            
            needOperationType = .Srtoke
            
//        }else if lastObject! is CGPath {
//
//            needOperationType = .MosaicFuzzy
//        }
            
        }else {
            
            needOperationType = .MosaicFuzzy
        }

        
    
        allPathArray.removeLast()
        
        
        switch needOperationType {
        
        case .Srtoke:
            
            if allPathArray.count == 0 {
                strokePath = CGMutablePath.init()
            }
            setNeedsDisplay()
            
        case .MosaicFuzzy:
            
            if allPathArray.count > 0 {
                
                for (_,value) in allPathArray.enumerated().reversed() where value.isKind(of: LMImageSrtoke.self) == false {
                    
                    let mosaicFuzzy:CGPath = value as! CGPath
                    
                    mosaicFuzzyShapeLayer.path = mosaicFuzzy
                    mosaicFuzzyPath = mosaicFuzzy.mutableCopy()!
        
                    break
                }
               
            }else{
                
                mosaicFuzzyShapeLayer.path = nil
                mosaicFuzzyPath = CGMutablePath.init()
            }
        
        default:
            break
        }
        
        
    }
    
    //MARK: Event & Action
}








